using System;
using System.Collections.Generic;
using System.Diagnostics;
using Apache.Cassandra;
using Cassandraemon.Builder;


namespace Cassandraemon.Operators
{


	class MultigetCountCassandraOperator<T> : CassandraOperatorBase<T>
	{
		public List<byte[]> Keys { get; set; }
		
		public ColumnParent ColumnParent { get; set; }
		
		public SlicePredicate Predicate { get; set; }
	
		public ConsistencyLevel ConsistencyLevel { get; set; }
	
	
		public MultigetCountCassandraOperator () { }
		
		
		protected override object OperateInner ()
		{
            var ctx = this.Context;
            var sw = Stopwatch.StartNew();
            Dictionary<byte[], int> countDic;
            try {
                countDic = Client.multiget_count(Keys, ColumnParent, Predicate, ConsistencyLevel);
            } catch (Exception err) {
                ctx.OnExecuted(CassandraExecuteEventArgs.FromOperation(this, err, sw));
                throw;
            }
            ctx.OnExecuted(CassandraExecuteEventArgs.FromOperation(this, countDic, sw));
			
			if(typeof(T).Name == "Dictionary`2")
			{
				return countDic;
			}
			else
			{
				throw new InvalidOperationException("You specify not Dictionary type to CassandraEntity's GenericType in multiget_count operation."); 
			}
		}

#if TRACE
        protected internal override void GetTraceData(List<object> data)
        {
            base.GetTraceData(data);
            data.Add("multiget_count");
            var cp = this.ColumnParent;
            data.Add(cp.Column_family);
        }
#endif

		public static ICassandraOperator<T> Create(CassandraOperatorCondition<T> condition)
		{
			if(condition.IsSetKey) throw new InvalidOperationException("You can't specify Key in case of multiget_count operation.");
			if(!condition.IsSetKeys) throw new InvalidOperationException("You must specify Keys in case of multiget_count operation.");
			
			if(condition.EqIndexExpression.Count  > 0 ||
			   condition.GteIndexExpression.Count > 0 ||
			   condition.GtIndexExpression.Count  > 0 ||
			   condition.LteIndexExpression.Count > 0 ||
			   condition.LtIndexExpression.Count  > 0)
				throw new InvalidOperationException("You can't specify index in case of multiget_count operation.");
				
			if(condition.IsSetStartKey || 
			   condition.IsSetFinishKey || 
			   condition.IsSetStartToken || 
			   condition.IsSetFinishToken ||
			   condition.IsSetKeyCount)
				throw new InvalidOperationException("You can't specify range key in case of multiget_count operation.");
			
			if(condition.IsSetColumns &&
			  (condition.IsSetStartColumn || 
			   condition.IsSetFinishColumn || 
			   condition.IsSetReverse ||
			   condition.IsSetCount))
				throw new InvalidOperationException("You can't specify both Columns and range column in case of multiget_count operation.");
			
				
			var oper = new MultigetCountCassandraOperator<T>();
			
			oper.Keys = condition.Keys;
			oper.ConsistencyLevel = condition.ConsistencyLevel;
			oper.PostProcessor = condition.PostProcessor;
			
			oper.ColumnParent = new ColumnParent();
			oper.ColumnParent.Column_family = condition.ColumnFamily;
			oper.ColumnParent.Super_column = condition.SuperColumn;
			
			oper.Predicate = new SlicePredicate();
			oper.Predicate.Column_names = condition.Columns;
			if(condition.Columns == null)
			{
				oper.Predicate.Slice_range = new SliceRange();
				oper.Predicate.Slice_range.Start = condition.StartColumn;
				oper.Predicate.Slice_range.Finish = condition.FinishColumn;
				oper.Predicate.Slice_range.Reversed = condition.Reverse;
				oper.Predicate.Slice_range.Count = condition.Count;
			}	
			
			Type type = typeof(T);
			
			if(type.Name == "Dictionary`2")
		   	{
		   		// Do Nothing
			}
			else
			{
				throw new InvalidOperationException("Return type specified not Dictionary type in multiget_count operation."); 
			}
			
			return oper;
		}

	}
}
